/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.staf.NetworkReportGenerator;

import java.io.File;
import java.io.FilenameFilter;
import java.io.FileInputStream;
import java.io.IOException;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;

import java.util.TreeSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author aezhov
 */
public class NmapXMLParser extends DefaultHandler implements FilenameFilter {
    enum States {NULL, ROOT, IN_HOST, IN_UP_HOST};

    String fileSep = System.getProperty("file.separator");
    States parseState = States.NULL;
    String ip = null;
    String mac = null;
    String spoolDirName = null;
    TreeSet<String> ipSet = new TreeSet<String>();
    HashMap<String, TreeSet<String>> macMap = new HashMap<String, TreeSet<String>>();
    
    public NmapXMLParser(String spoolDirName) throws ConfigurationException,
        org.xml.sax.SAXException, java.io.FileNotFoundException,
        java.io.IOException
    {
        this.spoolDirName = spoolDirName;

        if (spoolDirName == null || spoolDirName.length() == 0)
            throw new ConfigurationException("Nmap spool is not defined");

        File spoolDir = new File(spoolDirName);
        if (!spoolDir.isDirectory())
            throw new ConfigurationException("Defined nmap spool is not a dir " +
                    "or doesn't exist");

        String[] filenames = spoolDir.list(this);
        System.out.println("=== Constructing NmapXML Parser. Found " + filenames.length + " filenames");
        for (int i = 0; i < filenames.length; i++) {
            System.out.println("  Parsing " + filenames[i]);
            File toParse = new File(spoolDirName + fileSep + filenames[i]);
            XMLReader parser = XMLReaderFactory.createXMLReader();
            parser.setContentHandler(this);
            parser.parse(new InputSource(new FileInputStream(toParse)));
        }
    }

    public Map getMacMap() {
        return macMap;
    }

    public TreeSet ipSet() {
        return ipSet;
    }

    public Set getIpsForMac(String mac) {
        TreeSet<String> ips = macMap.get(mac);
        return ips;
    }

    public String getSpoolDir() {
        return spoolDirName;
    }

    // DefaultHandler methods redefenition
    public void startDocument() {
        parseState = States.ROOT;
    }

    public void endDocument() {
        parseState = States.NULL;
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        String worker = null;

        if (qName.equals("host") && parseState == States.ROOT)
            parseState = States.IN_HOST;
        else if (qName.equals("status") && parseState == States.IN_HOST) {
            worker = attributes.getValue("state");
            if (worker.equals("up")) 
                parseState = States.IN_UP_HOST;
        } else if (qName.equals("address") && parseState == States.IN_UP_HOST) {
            worker = attributes.getValue("addrtype");
            if (worker.equals("ipv4")) 
                ip = attributes.getValue("addr");
            else if (worker.equals("mac")) 
                mac = attributes.getValue("addr");

            if (ip != null && mac != null) {
                parseState = States.IN_HOST;
                ipSet.add(ip);
                TreeSet<String> ips = macMap.get(mac);
                if (ips == null) {
                    ips = new TreeSet<String>();
                    macMap.put(mac, ips);
                }
                ips.add(ip);

                ip = null;
                mac = null;
            }
        }
    }

    public void endElement(String uri, String localName, String qName) {
        if (qName.equals("host") && parseState == States.IN_HOST)
            parseState = States.ROOT;
    }

    // Filename filter implementation
    public boolean accept(File dir, String name) {
        return name.matches("n\\d+\\.xml");
    }
}
